package wahadlo;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Label;
import java.awt.Panel;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.ButtonGroup;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.JTextField;

public class Wahadlo extends JApplet implements Runnable, ActionListener,
		ItemListener {
	// deklaracja wszystkich zmiennych
	private static final long serialVersionUID = 1L;
	private volatile Thread th;
	private boolean onFlag, chkpause, onApprox;
	private Container con;
	private Panel btnmenu, cbxmenu;
	private JButton bStart, bPause, bReset, bAbout;
	private JTextField tfI, tfM, tfAlfa0, tfD, tfG;
	// x(t), V(t), energia kin., energia pot., energia cał., przesunięcie
	// fazowe, przybliżenie małych kątów.
	private JCheckBox cbX_t, cbV_t, cbEk_t, cbEp_t, cbE, cbPhase, cbApprox;

	private Label lI, lM, lAlfa0, lD, lG, lApprox;
	private double I, m, G, d, T, t, dt, Alfa0, a0, oldAlfa, oldOmega, alfa,
			omega, oldT;
	private int Xmin, Xmax, Ymin, Ymax;
	private double Xinf, Yinf, Xsup, Ysup;
	private double rx1, rx2, ry1, ry2, ax1, ax2, ay1, ay2;
	int x, y, nr = 0, nT = 2;
	Color color;
	private Graphics gCanvas;
	private Graphics gBuff;
	Image iBuff;

	double t1, t2;

	// inicjalizacja zmiennych i ustawienie wygladu apletu
	public void init() {
		color = new Color(80, 95, 170);
		this.setSize(new Dimension(800, 600));

		con = this.getContentPane();
		con.setLayout(null);
		con.setBackground(Color.white);

		// Panel Menu
		btnmenu = new Panel();
		btnmenu.setBackground(color);
		btnmenu.setLayout(null);
		btnmenu.setBounds(this.getWidth() - 170, 0, this.getWidth(), this
				.getHeight() - 60);

		bStart = new JButton(" Start ");
		bStart.setBounds(10, 10, 150, 25);
		btnmenu.add(bStart);
		bStart.addActionListener(this);

		bPause = new JButton("Pause");
		bPause.setBounds(10, 45, 150, 25);
		bPause.setEnabled(false);
		btnmenu.add(bPause);
		bPause.addActionListener(this);

		bReset = new JButton(" Reset ");
		bReset.setBounds(10, 80, 150, 25);
		bReset.setEnabled(false);
		btnmenu.add(bReset);
		bReset.addActionListener(this);

		lM = new Label("Masa wahad�a");
		lM.setForeground(Color.white);
		lM.setBounds(10, 130, 150, 20);
		btnmenu.add(lM);
		tfM = new JTextField();
		tfM.setBounds(10, 155, 100, 25);
		tfM.setHorizontalAlignment(JTextField.RIGHT);
		tfM.addActionListener(this);
		btnmenu.add(tfM);
		lM = new Label("[kg]");
		lM.setForeground(Color.white);
		lM.setBounds(115, 155, 150, 20);
		btnmenu.add(lM);

		lI = new Label("Moment bezw�adno�ci");
		lI.setForeground(Color.white);
		lI.setBounds(10, 190, 190, 20);
		btnmenu.add(lI);
		tfI = new JTextField();
		tfI.setBounds(10, 215, 100, 25);
		tfI.setHorizontalAlignment(JTextField.RIGHT);
		tfI.addActionListener(this);
		btnmenu.add(tfI);
		lI = new Label("[kg*m2]");
		lI.setForeground(Color.white);
		lI.setBounds(115, 215, 50, 25);
		btnmenu.add(lI);

		lD = new Label("Odl. od �rodka masy");
		lD.setForeground(Color.white);
		lD.setBounds(10, 250, 150, 20);
		btnmenu.add(lD);
		tfD = new JTextField();
		tfD.setBounds(10, 275, 100, 25);
		tfD.setHorizontalAlignment(JTextField.RIGHT);
		tfD.addActionListener(this);
		btnmenu.add(tfD);
		lD = new Label("[m]");
		lD.setForeground(Color.white);
		lD.setBounds(115, 275, 50, 25);
		btnmenu.add(lD);

		lAlfa0 = new Label("Wychylenie pocz�tkowe");
		lAlfa0.setForeground(Color.white);
		lAlfa0.setBounds(10, 310, 150, 20);
		btnmenu.add(lAlfa0);
		tfAlfa0 = new JTextField();
		tfAlfa0.setBounds(10, 335, 100, 25);
		tfAlfa0.setHorizontalAlignment(JTextField.RIGHT);
		tfAlfa0.addActionListener(this);
		btnmenu.add(tfAlfa0);
		lAlfa0 = new Label("[�]");
		lAlfa0.setForeground(Color.white);
		lAlfa0.setBounds(115, 335, 150, 20);
		btnmenu.add(lAlfa0);

		lG = new Label("Grawitacja");
		lG.setForeground(Color.white);
		lG.setBounds(10, 370, 150, 20);
		btnmenu.add(lG);
		tfG = new JTextField();
		tfG.setBounds(10, 395, 100, 25);
		tfG.setHorizontalAlignment(JTextField.RIGHT);
		tfG.addActionListener(this);
		btnmenu.add(tfG);
		lG = new Label("[m/s2]");
		lG.setForeground(Color.white);
		lG.setBounds(115, 395, 150, 20);
		btnmenu.add(lG);

		lApprox = new Label("Przybli�enie ma�ych k�t�w");
		lApprox.setForeground(Color.red);
		lApprox.setBounds(10, 450, 150, 20);
		btnmenu.add(lApprox);
		cbApprox = new JCheckBox("W�. / Wy�.");
		cbApprox.setBackground(color);
		cbApprox.setForeground(Color.red);
		cbApprox.setBounds(10, 475, 80, 25);
		cbApprox.setSelected(false);
		cbApprox.addItemListener(this);
		btnmenu.add(cbApprox);

		add("East", btnmenu);

		// Panel cbxmenu
		cbxmenu = new Panel();
		cbxmenu.setBackground(color);
		cbxmenu.setLayout(null);
		cbxmenu.setBounds(0, this.getHeight() - 60, this.getWidth(), this
				.getHeight());

		cbX_t = new JCheckBox("Wychylenie");
		cbX_t.setBounds(10, 18, 100, 25);
		cbX_t.setBackground(color);
		cbX_t.setForeground(Color.white);
		cbX_t.setSelected(false);
		cbX_t.addItemListener(this);
		cbxmenu.add(cbX_t);

		cbV_t = new JCheckBox("Pr�dko��");
		cbV_t.setBounds(110, 18, 90, 25);
		cbV_t.setBackground(color);
		cbV_t.setForeground(Color.white);
		cbV_t.setSelected(false);
		cbV_t.addItemListener(this);
		cbxmenu.add(cbV_t);

		cbEk_t = new JCheckBox("En. kin.");
		cbEk_t.setBounds(200, 18, 70, 25);
		cbEk_t.setBackground(color);
		cbEk_t.setForeground(Color.white);
		cbEk_t.setSelected(false);
		cbEk_t.addItemListener(this);
		cbxmenu.add(cbEk_t);

		cbEp_t = new JCheckBox("En. pot.");
		cbEp_t.setBounds(270, 18, 70, 25);
		cbEp_t.setBackground(color);
		cbEp_t.setForeground(Color.white);
		cbEp_t.setSelected(false);
		cbEp_t.addItemListener(this);
		cbxmenu.add(cbEp_t);

		cbE = new JCheckBox("En. ca�kowita");
		cbE.setBounds(350, 18, 100, 25);
		cbE.setBackground(color);
		cbE.setForeground(Color.white);
		cbE.setSelected(false);
		cbE.addItemListener(this);
		cbxmenu.add(cbE);

		cbPhase = new JCheckBox("Przestrze� fazowa");
		cbPhase.setBounds(460, 18, 140, 25);
		cbPhase.setBackground(color);
		cbPhase.setForeground(Color.white);
		cbPhase.setSelected(false);
		cbPhase.addItemListener(this);
		cbxmenu.add(cbPhase);

		bAbout = new JButton("O autorach");
		bAbout.setBounds(660, 18, 100, 25);
		cbxmenu.add(bAbout);
		bAbout.addActionListener(this);

		ButtonGroup group = new ButtonGroup();
		group.add(cbX_t);
		group.add(cbV_t);
		group.add(cbEk_t);
		group.add(cbEp_t);
		group.add(cbE);
		group.add(cbPhase);

		add("South", cbxmenu);

		Xmin = 50;
		Xmax = 450;
		Ymin = 20;
		Ymax = 280;
		tfM.setText("10");
		tfI.setText("1000");
		tfD.setText("1");
		tfAlfa0.setText("50");
		tfG.setText("9.81");
		oldOmega = 0;
		oldT = 0;
		t = 0.0;
		iBuff = createImage(800 - 170, 600 - 60);
		gBuff = iBuff.getGraphics();
		onFlag = false;
		chkpause = false;
		onApprox = false;

		t1 = 1;
		t2 = 0;
	}

	public void start() {
		th = new Thread(this);
		th.start();
	}

	public void stop() {
		removeAll();
		th = null;
	}

	// procedura odpowiedzialna za rysowanie wykresu i ruch wahadla gdy zmienna
	// onFlag ma wartosc true
	public void run() {
		Thread thisThread = Thread.currentThread();
		while (th == thisThread) {
			try {
				Thread.sleep(15);
			} catch (InterruptedException e) {
			}
			if (onFlag) {
				t += dt;
				drawcoord();
				plotxy();
				gBuff.setColor(Color.white);
				gBuff.fillRect(0, Ymax + 1, 800, 600 - Ymax);
				wahadlo();
			}
		}
	}

	// procedura odpowiadajaca za animacje wahadla
	public void wahadlo() {
		gCanvas = this.getGraphics();
		Graphics2D g = (Graphics2D) gCanvas;
		Graphics2D gB = (Graphics2D) gBuff;
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g.setRenderingHint(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY);
		gB.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		gB.setRenderingHint(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY);
		gBuff.setColor(Color.black);
		gBuff.fillRect(290, Ymax + 110, 20, 5);
		x = (int) (300 + 100 * Math.sin(oldAlfa));
		y = (int) (Ymax + 110 + 100 * Math.cos(oldAlfa));
		gBuff.drawLine(300, Ymax + 110, x, y);
		gBuff.setColor(Color.red);
		gBuff.fillOval(x - 5, y - 5, 10, 10);
		g.drawImage(iBuff, 0, 0, this);
	}

	// procedury przeskalowujace wyliczone wartosci do wspolrzednych na wykresie
	private int coordToPixX(double x) {
		return (int) (Xmin + ((Xmax - 20 - Xmin) * (x - Xinf) / (Xsup - Xinf)));
	}

	private int coordToPixXphase(double x) {
		return (int) (Xmin + 20 + ((Xmax - 40 - Xmin) * (x - Xinf) / (Xsup - Xinf)));
	}

	private int coordToPixY(double y) {
		return (int) ((Ymax - 20) - (Ymax - Ymin - 40) * (y - Yinf)
				/ (Ysup - Yinf));
	}

	// ustawia minimalne i maksymalne wartosci dla osi wspolrzednych
	public void calculatemax(double xi, double xm, double ym) {
		Xinf = xi;
		Yinf = -ym;
		Xsup = xm;
		Ysup = ym;
	}

	// zamienia wartosc liczby na napis z mozliwoscia wybrania liczby miejsc po
	// przecinku
	public String doubleToString(double a, int n) {
		int b, p, i;
		String s = (a >= 0 ? "" : "-");
		if (a < 0)
			a = -a;
		for (i = 0, p = 1; i < n; i++)
			p *= 10;
		b = (int) (a * p + 0.5);
		s += b / p;
		if (n > 0)
			s += ".";
		b = b % p;
		for (i = 0; i < n; i++) {
			p /= 10;
			s += b / p;
			b = b % p;
		}
		return s;
	}

	// zwraca wartosc prawej strony rownania ruchu wahadla
	public double funkcja(double y) {
		return (-(G / (I / (m * d))) * Math.sin(y));
	}

	// procedura wyliczajaca kolejne wartosci katow ulepszona metoda Eulera
	// oraz w zaleznosci od wybranego typu wykresu wartosci predkosci katowej,
	// energii kinetycznej lub potencjalnej
	public void calculatexy() {
		alfa = oldAlfa + dt * (oldOmega + (dt / 2) * funkcja(oldAlfa));
		omega = oldOmega + dt * funkcja(oldAlfa + oldOmega * (dt / 2));
		if (alfa > Alfa0)
			alfa = Alfa0;
		if (nr == 1) {
			calculatemax((nT - 2) * T, nT * T, Alfa0);
			ry1 = oldAlfa;
			ry2 = alfa;
			ay1 = Alfa0 * Math.cos(Math.sqrt(G / (I / (m * d))) * oldT);
			ay2 = Alfa0 * Math.cos(Math.sqrt(G / (I / (m * d))) * t);
		}
		if (nr == 2) {
			calculatemax((nT - 2) * T, nT * T, Math.sqrt(G / (I / (m * d)))
					* Alfa0);
			ry1 = oldOmega;
			ry2 = omega;
			ay1 = -Math.sqrt(G / (I / (m * d))) * Alfa0
					* Math.sin(Math.sqrt(G / (I / (m * d))) * (oldT));
			ay2 = -Math.sqrt(G / (I / (m * d))) * Alfa0
					* Math.sin(Math.sqrt(G / (I / (m * d))) * (t));
		}
		if (nr == 3) {
			calculatemax((nT - 2) * T, nT * T, m * G * (I / (m * d))
					* (1 - Math.cos(Alfa0)));
			ry1 = m * G * (I / (m * d)) * (Math.cos(oldAlfa) - Math.cos(Alfa0));
			ry2 = m * G * (I / (m * d)) * (Math.cos(alfa) - Math.cos(Alfa0));
			ay1 = m
					* G
					* (I / (m * d))
					* (Math.cos(Alfa0
							* Math.cos(Math.sqrt(G / (I / (m * d))) * (oldT))) - Math
							.cos(Alfa0));
			ay2 = m
					* G
					* (I / (m * d))
					* (Math.cos(Alfa0
							* Math.cos(Math.sqrt(G / (I / (m * d))) * (t))) - Math
							.cos(Alfa0));
		}
		if (nr == 4) {
			calculatemax((nT - 2) * T, nT * T, m * G * (I / (m * d))
					* (1 - Math.cos(Alfa0)));
			ry1 = m * G * (I / (m * d)) * (1 - Math.cos(oldAlfa));
			ry2 = m * G * (I / (m * d)) * (1 - Math.cos(alfa));
			ay1 = m
					* G
					* (I / (m * d))
					* (1 - Math.cos(Alfa0
							* Math.cos(Math.sqrt(G / (I / (m * d))) * (oldT))));
			ay2 = m
					* G
					* (I / (m * d))
					* (1 - Math.cos(Alfa0
							* Math.cos(Math.sqrt(G / (I / (m * d))) * (t))));
		}
		if (nr == 5) {
			calculatemax((nT - 2) * T, nT * T, m * G * (I / (m * d))
					* (1 - Math.cos(Alfa0)));
			ry1 = m
					* G
					* (I / (m * d))
					* ((Math.cos(oldAlfa) - Math.cos(Alfa0)) + (1 - Math
							.cos(oldAlfa)));
			ry2 = m
					* G
					* (I / (m * d))
					* ((1 - Math.cos(alfa)) + (Math.cos(alfa) - Math.cos(Alfa0)));
			ay1 = m
					* G
					* (I / (m * d))
					* ((1 - Math.cos(Alfa0
							* Math.cos(Math.sqrt(G / (I / (m * d))) * (oldT)))) + (Math
							.cos(Alfa0
									* Math.cos(Math.sqrt(G / (I / (m * d)))
											* (oldT))) - Math.cos(Alfa0)));
			ay2 = m
					* G
					* (I / (m * d))
					* ((1 - Math.cos(Alfa0
							* Math.cos(Math.sqrt(G / (I / (m * d))) * (t)))) + (Math
							.cos(Alfa0
									* Math.cos(Math.sqrt(G / (I / (m * d)))
											* (t))) - Math.cos(Alfa0)));
		}
		if (nr == 6) {
			calculatemax(-Math.sqrt(G / (I / (m * d))) * Alfa0, Math.sqrt(G
					/ (I / (m * d)))
					* Alfa0, Alfa0);
			rx1 = oldOmega;
			rx2 = omega;
			ry1 = oldAlfa;
			ry2 = alfa;
			ax1 = -Math.sqrt(G / (I / (m * d))) * Alfa0
					* Math.sin(Math.sqrt(G / (I / (m * d))) * (oldT));
			ax2 = -Math.sqrt(G / (I / (m * d))) * Alfa0
					* Math.sin(Math.sqrt(G / (I / (m * d))) * (t));
			ay1 = Alfa0 * Math.cos(Math.sqrt(G / (I / (m * d))) * (oldT));
			ay2 = Alfa0 * Math.cos(Math.sqrt(G / (I / (m * d))) * (t));
		}
		if (nr != 6) {
			rx1 = oldT;
			rx2 = t;
			ax1 = oldT;
			ax2 = t;
		}
		oldAlfa = alfa;
		oldOmega = omega;
		oldT = t;
	}

	// procedura rysujaca wybrany wykres dla aktualnie wyliczonych wartosci
	public void plotxy() {
		gCanvas = this.getGraphics();
		Graphics2D g = (Graphics2D) gCanvas;
		calculatexy();
		drawunits();
		gBuff.setColor(Color.black);
		if (nr == 6) {
			gBuff.drawLine(coordToPixXphase(rx1), coordToPixY(ry1),
					coordToPixXphase(rx2), coordToPixY(ry2));
		}
		if (nr != 6) {
			gBuff.drawLine(coordToPixX(rx1), coordToPixY(ry1),
					coordToPixX(rx2), coordToPixY(ry2));
		}
		if (onApprox == true) {
			gBuff.setColor(Color.red);
			if (nr != 6) {
				gBuff.drawLine(coordToPixX(ax1), coordToPixY(ay1),
						coordToPixX(ax2), coordToPixY(ay2));
			}
			if (nr == 6) {
				gBuff.drawLine(coordToPixXphase(ax1), coordToPixY(ay1),
						coordToPixXphase(ax2), coordToPixY(ay2));
			}
		}
		if ((t >= nT * T) && (nr != 6)) {
			nT += 2;
			gBuff.setColor(Color.white);
			gBuff.fillRect(0, 0, 800, 600);
		}
		g.drawImage(iBuff, 0, 0, this);
	}

	// procedura rysujaca wahadlo i osie wspolrzednych zaraz po uruchomieniu
	// apletu
	public void paint(Graphics g) {
		drawcoord();
		wahadlo();
	}

	// procedura rysujaca osie wspolrzednych
	public void drawcoord() {
		int x1 = 0, y1 = 0, y2 = 0;
		gCanvas = this.getGraphics();
		Graphics2D g = (Graphics2D) gCanvas;
		//Graphics2D gB = (Graphics2D) gBuff;
		gBuff.setColor(Color.black);
		if (nr != 6) {
			x1 = Xmin;
			y1 = Ymin;
			y2 = Ymax;
		}
		if (nr == 6) {
			x1 = Xmin + (Xmax - Xmin - 0) / 2 + 1;
			y1 = Ymin;
			y2 = Ymax;
		}
		gBuff.drawLine(x1 - 2, y1, x1 - 2, y2);
		gBuff.drawLine(x1 - 1, y1, x1 - 1, y2);
		gBuff.drawLine(x1, y1, x1, y2);
		gBuff.drawLine(Xmin, Ymin + ((Ymax - Ymin) / 2) - 1, Xmax, Ymin
				+ ((Ymax - Ymin) / 2) - 1);
		gBuff.drawLine(Xmin, Ymin + ((Ymax - Ymin) / 2), Xmax, Ymin
				+ ((Ymax - Ymin) / 2));
		gBuff.drawLine(Xmin, Ymin + ((Ymax - Ymin) / 2) + 1, Xmax, Ymin
				+ ((Ymax - Ymin) / 2) + 1);
		int xp1[] = { Xmax, Xmax, Xmax + 5 };
		int yp1[] = { Ymin + (Ymax - Ymin) / 2 - 5,
				Ymin + (Ymax - Ymin) / 2 + 5, Ymin + (Ymax - Ymin) / 2 };
		int xp2[] = { x1 - 6, x1 + 5, x1 - 1 };
		int yp2[] = { Ymin, Ymin, Ymin - 5 };
		gBuff.fillPolygon(xp1, yp1, 3);
		gBuff.fillPolygon(xp2, yp2, 3);
		if (nr != 6) {
			for (int i = Xmin; i <= Xmax - 20; i += (Xmax - Xmin - 20) / 5)
				gBuff.drawLine(i, Ymin + ((Ymax - Ymin) / 2) - 3, i, Ymin
						+ ((Ymax - Ymin) / 2) + 3);
		}
		if (nr == 6) {
			for (int i = Xmin + 20; i <= Xmax - 20; i += ((Xmax - Xmin - 40) / 2) / 3)
				gBuff.drawLine(i, Ymin + ((Ymax - Ymin) / 2) - 3, i, Ymin
						+ ((Ymax - Ymin) / 2) + 3);
		}
		for (int i = Ymin + 20; i <= Ymax - 20; i += (Ymin
				+ ((Ymax - Ymin) / 2) - (Ymin + 20)) / 5)
			gBuff.drawLine(x1 - 4, i, x1 + 2, i);
		g.drawImage(iBuff, 0, 0, this);
	}

	// procedura odpowiedzialna za wypisywanie wartosci liczbowych na osiach
	public void drawunits() {
		int x1 = 0, y1 = 0, y2 = 0;
		gCanvas = this.getGraphics();
		Graphics2D g = (Graphics2D) gCanvas;
		gBuff.setColor(Color.black);
		double max = 0;
		int dx = (Xmax - Xmin - 20) / 5;
		int dx2 = (Xmax - Xmin - 40) / 5;
		int dy = (Ymin + ((Ymax - Ymin) / 2) - (Ymin + 20)) / 5;
		double alpha = Alfa0 * 180 / Math.PI;
		if ((nr == 1) || (nr == 5))
			max = alpha;
		if (nr == 2)
			max = Math.sqrt(G / (I / (m * d))) * alpha;
		if (nr == 3)
			max = m * G * (I / (m * d)) * (1 - Math.cos(Alfa0));
		if (nr == 4)
			max = Ysup;
		if (nr == 5)
			max = m * G * (I / (m * d)) * (1 - Math.cos(Alfa0));
		if (nr != 6) {
			for (int i = Xmin + dx; i <= Xmax - 20; i += dx)
				if (nr != 6)
					gBuff.drawString(doubleToString((nT - 2) * T
							+ ((i - Xmin) * 2 * T / (Xmax - Xmin - 20)), 1),
							i - 12, Ymin + ((Ymax - Ymin) / 2 + 20));
		}
		if (nr == 6) {
			for (int i = Xmin + 20; i <= Xmax - 20; i += dx2)
				gBuff.drawString(doubleToString(
						(-Math.sqrt(G / (I / (m * d))) * a0) + (i - Xmin - 20)
								* 2 * Math.sqrt(G / (I / (m * d))) * a0
								/ (Xmax - Xmin - 40), 1), i - 12, Ymin
						+ ((Ymax - Ymin) / 2 + 20));
		}
		if (nr != 6) {
			x1 = Xmin;
			y1 = Ymin;
			y2 = Ymax;
			gBuff.drawString("t[s]", Xmax, 20 + Ymin + ((Ymax - Ymin) / 2));
		}
		if (nr == 6) {
			x1 = Xmin + (Xmax - Xmin - 20) / 2 + 1;
			y1 = Ymin;
			y2 = Ymax;
			gBuff.drawString("\u03c9[\u00b0/s]", Xmax, 20 + Ymin
					+ ((Ymax - Ymin) / 2));
		}
		for (int i = y1 + 20; i <= y2 - 20; i += dy)
			gBuff.drawString(doubleToString(max - (i - y1 - 20) * 2 * max
					/ (y2 - y1 - 40), 0), x1 - 35, i + 5);
		switch (nr) {
		case 1:
			gBuff.setColor(Color.black);
			gBuff.drawString("[\u00b0]", Xmin - 25, Ymin + 5);
			break;
		case 2:
			gBuff.setColor(Color.black);
			gBuff.drawString("\u03c9[\u00b0/s]", Xmin - 35, Ymin + 5);
			break;
		case 3:
			gBuff.setColor(Color.black);
			gBuff.drawString("Ek[J]", Xmin - 35, Ymin + 5);
			break;
		case 4:
			gBuff.setColor(Color.black);
			gBuff.drawString("Ep[J]", Xmin - 35, Ymin + 5);
			break;
		case 5:
			gBuff.setColor(Color.black);
			gBuff.drawString("E[J]", Xmin - 35, Ymin + 5);
			break;
		case 6:
			gBuff.setColor(Color.black);
			gBuff.drawString("[\u00b0]", Xmin + (Xmax - Xmin - 20) / 2 - 30,
					Ymin + 5);
			break;
		}
		g.drawImage(iBuff, 0, 0, this);
	}

	// procedura czyszczaca pole wykresu
	public void clear() {
		gCanvas = this.getGraphics();
		Graphics2D g = (Graphics2D) gCanvas;
		gBuff.setColor(Color.white);
		gBuff.fillRect(0, 0, 800, 600);
		g.drawImage(iBuff, 0, 0, this);
	}

	// procedura odpowiedzialna za obsluge zdarzen po nacisnieciu danego
	// przycisku
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == bStart) {
			String tM = tfM.getText();
			m = Double.parseDouble(tM);
			String tI = tfI.getText();
			I = Double.parseDouble(tI);
			String tD = tfD.getText();
			d = Double.parseDouble(tD);
			String tA0 = tfAlfa0.getText();
			a0 = Double.parseDouble(tA0);
			Alfa0 = (Double.parseDouble(tA0) * Math.PI) / 180;
			String tG = tfG.getText();
			G = Double.parseDouble(tG);
			// T=2*Math.PI*Math.sqrt(I/(m*G*d))*(1+0.5*0.5*Math.pow(Math.sin(Alfa0/2),2.0)+
			// (3/8)*(3/8)*Math.pow(Math.sin(Alfa0/2),4.0));
			for (double i = 0; i <= 60; i++) {
				for (double j = 0; j <= i; j++) {
					t1 *= ((2 * j + 1) / (2 * j + 2))
							* ((2 * j + 1) / (2 * j + 2));
				}
				t2 += t1 * Math.pow(Math.sin(Alfa0 / 2), 2 * i + 2);
				t1 = 1;
			}
			T = 2 * Math.PI * Math.sqrt(I / (m * G * d)) * (1 + t2);
			dt = 2 * T / ((Xmax - Xmin - 20) / 3);
			if (Math.abs(a0) > 170 || m <= 0 || nr == 0 || I <= 0 || d <= 0
					|| G <= 0)
				JOptionPane.showMessageDialog(null,
						"Niew�a�ciwe parametry\nlub nie wybrano typu wykresu!",
						"B��d", JOptionPane.ERROR_MESSAGE);
			else {
				onFlag = true;
				oldAlfa = Alfa0;
				oldOmega = 0;
				oldT = 0;
				bReset.setEnabled(true);
				bStart.setEnabled(false);
				bPause.setEnabled(true);
			}
		} else if ((e.getSource() == bPause) && chkpause == false) {
			onFlag = !onFlag;
			chkpause = true;
			bPause.setText("Resume");
		} else if ((e.getSource() == bPause) && chkpause == true) {
			onFlag = !onFlag;
			chkpause = false;
			bPause.setText("Pause");
		} else if (e.getSource() == bReset) {
			onFlag = false;
			t = 0;
			t1 = 1;
			t2 = 0;
			nT = 2;
			oldT = 0;
			clear();
			repaint();
			bReset.setEnabled(false);
			bStart.setEnabled(true);
			bPause.setEnabled(false);
		} else if (e.getSource() == bAbout) {
			String about = "Warsztaty z fizyki komputerowej\nrok akademicki 2005/2006\n\n"
					+ "                    Autorzy:\n"
					+ "            Konrad G�rnicki\n"
					+ "      konradgornicki@wp.pl\n\n"
					+ "                Maciej Bylina\n"
					+ "             m_bylina@o2.pl\n\n"
					+ "Opiekun: prof. Ryszard Kutner";
			JOptionPane.showMessageDialog(null, about, "O autorach",
					JOptionPane.INFORMATION_MESSAGE);
		}
	}

	// procedura ustawiajaca znacznik nr na konkretna wartosc w zaleznosci od
	// wybranego wykresu
	public void itemStateChanged(ItemEvent e) {
		if (cbX_t.isSelected()) {
			nr = 1;
			clear();
			repaint();
		} else if (cbV_t.isSelected()) {
			nr = 2;
			clear();
			repaint();
		} else if (cbEk_t.isSelected()) {
			nr = 3;
			clear();
			repaint();
		} else if (cbEp_t.isSelected()) {
			nr = 4;
			clear();
			repaint();
		} else if (cbE.isSelected()) {
			nr = 5;
			clear();
			repaint();
		} else if (cbPhase.isSelected()) {
			nr = 6;
			clear();
			repaint();
		}
		if (cbApprox.isSelected() == true)
			onApprox = true;
		else if (cbApprox.isSelected() == false)
			onApprox = false;
	}
}